#define _POSIX_C_SOURCE 199309L  //  确保这一行放在所有 #include 之前
#include <arpa/inet.h>
#include <sys/statvfs.h>
#include <math.h>
#include "utils.h"

#define MAX_SAMPLES 8

char* get_raspberry_pi_ip(char* buffer, size_t len) {
    FILE* fp;
    char line[512];

    fp = popen("hostname -I", "r");
    if (fp == NULL) {
        perror("Failed to run command");
        return NULL;
    }

    if (fgets(line, sizeof(line), fp) != NULL) {
        char *token = strtok(line, " ");
        while (token != NULL) {
            // 简单判断是否为 IPv4 地址（包含 . 并且能转换）
            if (strchr(token, '.') && inet_addr(token) != INADDR_NONE) {
                strncpy(buffer, token, len);
                buffer[len - 1] = '\0';
                pclose(fp);
                return buffer;
            }
            token = strtok(NULL, " ");
        }
    }

    strcpy(buffer, "No IPv4");
    pclose(fp);
    return buffer;
}

/**
 * 获取当前时间（秒）
 * @return 当前时间（秒）
 * #define _POSIX_C_SOURCE 199309L  //  确保这一行放在所有 #include 之前
 */
double get_current_time(void) {
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return (double)ts.tv_sec + (double)ts.tv_nsec / 1e9;
}


/**
 * 获取 CPU 温度（仅适用于 Linux 树莓派）
 * @param buffer 输出缓冲区
 * @param len 缓冲区长度
 * @return 成功返回 buffer，失败返回 NULL
 */
char* get_cpu_temperature(char* buffer, size_t len) {
    FILE* fp;
    double temp = 0.0;

    // 使用 vcgencmd 获取温度
    fp = popen("vcgencmd measure_temp | awk -F= '{print $2}' | tr -d \"'C\\n\"", "r");
    if (fp == NULL) {
        perror("Failed to run command");
        return NULL;
    }

    static double temperature_samples[MAX_SAMPLES] = {0};
    static int sample_count = 0;
    double sum = 0.0;

    if (fgets(buffer, len, fp)) {
        // 去除换行符等
        buffer[strcspn(buffer, "\n")] = '\0';
        sscanf(buffer, "%lf", &temp);

        // 添加新样本到数组并更新计数
        temperature_samples[sample_count % MAX_SAMPLES] = temp;
        sample_count++;

        // 计算平均值
        for (int i = 0; i < fmin(sample_count, MAX_SAMPLES); i++) {
            sum += temperature_samples[i];
        }
        temp = sum / fmin(sample_count, MAX_SAMPLES);
    } else {
        strcpy(buffer, "N/A");
    }

    pclose(fp);

    // 将平滑后的温度写入缓冲区
    snprintf(buffer, len, "%.1f", temp);
    return buffer;
}


/**
 * 获取内存使用情况，格式为 "used/total"
 * @param buffer 输出缓冲区
 * @param len 缓冲区长度
 * @return 成功返回 buffer，失败返回 NULL
 */
char* get_memory_usage(char* buffer, size_t len) {
    FILE* fp;
    char line[256];
    unsigned long total = 0, free = 0, buffers = 0, cached = 0;

    fp = fopen("/proc/meminfo", "r");
    if (!fp) {
        perror("Failed to open /proc/meminfo");
        return NULL;
    }

    while (fgets(line, sizeof(line), fp)) {
        sscanf(line, "MemTotal: %lu kB", &total);
        sscanf(line, "MemFree: %lu kB", &free);
        sscanf(line, "Buffers: %lu kB", &buffers);
        sscanf(line, "Cached: %lu kB", &cached);
    }

    fclose(fp);

    unsigned long used = total - free - buffers - cached;

    // 单位换算为 GB 或 MB
    double total_gb = total / (1024.0 * 1024.0);
    double used_gb = used / (1024.0 * 1024.0);

    if (total_gb >= 1.0) {
        snprintf(buffer, len, "%.1f/%.0fG", used_gb, total_gb);
    } else {
        snprintf(buffer, len, "%.1f/%.0fM", used_gb * 1024, total_gb * 1024);
    }

    return buffer;
}


/**
 * 获取 CPU 使用率百分比，并使用指数加权移动平均 (EWMA) 进行平滑处理
 * @param buffer 输出缓冲区
 * @param len 缓冲区长度
 * @return 成功返回 buffer，失败返回 NULL
 */
char* get_cpu_usage(char* buffer, size_t len) {
    FILE* fp;
    char line[256];
    unsigned long user = 0, nice = 0, system = 0, idle = 0, iowait = 0, irq = 0, softirq = 0;

    fp = fopen("/proc/stat", "r");
    if (!fp) {
        perror("Failed to open /proc/stat");
        return NULL;
    }

    if (fgets(line, sizeof(line), fp)) {
        sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu", &user, &nice, &system, &idle, &iowait, &irq, &softirq);
    }

    fclose(fp);

    unsigned long total_active = user + nice + system + irq + softirq;
    unsigned long total_idle = idle + iowait;
    unsigned long total = total_active + total_idle;

    static unsigned long prev_total = 0, prev_active = 0;
    static double smoothed_usage = 0.0;
    static int initialized = 0;

    if (!initialized) {
        prev_total = total;
        prev_active = total_active;
        initialized = 1;
        strcpy(buffer, "N/A");
        return buffer;
    }

    double total_diff = total - prev_total;
    double active_diff = total_active - prev_active;

    prev_total = total;
    prev_active = total_active;

    double cpu_percent = (active_diff / total_diff) * 100;

    // 使用 EWMA 平滑滤波（alpha 控制平滑程度）
    const double alpha = 0.3;  // 可调整：越小越平滑，越大响应越快
    smoothed_usage = alpha * cpu_percent + (1 - alpha) * smoothed_usage;

    snprintf(buffer, len, "%.1f%%", smoothed_usage);

    return buffer;
}

char* getCurrentSystemTime(char* buffer, size_t bufferSize) {
    time_t rawtime;
    struct tm * timeinfo;

    time(&rawtime);
    timeinfo = localtime(&rawtime);

    strftime(buffer, bufferSize, "%Y%m%d %H:%M:%S", timeinfo);

    return buffer;
}

/**
 * 获取磁盘使用情况，格式为 "used/total"
 * @param buffer 输出缓冲区
 * @param len 缓冲区长度
 * @return 成功返回 buffer，失败返回 NULL
 */
char* get_disk_usage(char* buffer, size_t len) {
    struct statvfs fs_info;

    // 获取根文件系统的磁盘信息
    if (statvfs("/", &fs_info) != 0) {
        perror("Failed to get disk info");
        strcpy(buffer, "N/A");
        return buffer;
    }

    unsigned long block_size = fs_info.f_frsize;             // 文件系统中每个块的大小（字节）
    unsigned long total_blocks = fs_info.f_blocks;           // 总块数
    unsigned long free_blocks = fs_info.f_bfree;             // 可用块数
    unsigned long used_blocks = total_blocks - free_blocks;  // 已用块数

    double total_size_gb = (double)(total_blocks * block_size) / (1024 * 1024 * 1024); // 转换为 GB
    double used_size_gb = (double)(used_blocks * block_size) / (1024 * 1024 * 1024);   // 转换为 GB

    // 根据总大小选择单位（GB 或 MB）
    if (total_size_gb >= 1.0) {
        snprintf(buffer, len, "%.0f/%.0fG", used_size_gb, total_size_gb);
    } else {
        double total_size_mb = total_size_gb * 1024;
        double used_size_mb = used_size_gb * 1024;
        snprintf(buffer, len, "%.0f/%.0fM", used_size_mb, total_size_mb);
    }

    return buffer;
}

